﻿@using DevExpress.Data.Filtering;
@using DevExpress.Data.Filtering.Helpers;

<DxListBox TData="CustomRangeFilterItem"
           TValue="CriteriaOperator"
           Data="Items"
           ValueFieldName="Criteria"
           TextFieldName="DisplayText"
           Values="SelectedValues"
           ValuesChanged="SelectedValues_Changed"
           SelectionMode="ListBoxSelectionMode.Multiple"
           ShowCheckboxes="true"
           CssClass="h-100" />

@code {
    [Parameter]
    public GridDataColumnFilterMenuTemplateContext FilterContext { get; set; }

    [Parameter]
    public IReadOnlyList<CustomRangeFilterItem> Items { get; set; }

    IEnumerable<CriteriaOperator> SelectedValues { get; set; }

    protected override void OnInitialized() {
        SelectedValues = LoadSelectedValues(
            FilterContext.FilterCriteria,
            Items.Select(i => i.Criteria).ToHashSet()
        );
    }

    void SelectedValues_Changed(IEnumerable<CriteriaOperator> value) {
        SelectedValues = value;
        FilterContext.FilterCriteria = CreateCriteria(SelectedValues);
    }

    static CriteriaOperator CreateCriteria(IEnumerable<CriteriaOperator> values) {
        var orderedValues = values.OrderBy(v => v.ToString()).ToArray();
        if (orderedValues.Length == 0)
            return null;

        return new GroupOperator(GroupOperatorType.Or, orderedValues);
    }
    static IEnumerable<CriteriaOperator> LoadSelectedValues(CriteriaOperator criteria, IReadOnlySet<CriteriaOperator> possibleCriterias) {
        if(possibleCriterias.Contains(criteria))
            return new[] { criteria };

        if(criteria is GroupOperator groupOp && groupOp.OperatorType == GroupOperatorType.Or && groupOp.Operands.All(i => possibleCriterias.Contains(i)))
            return groupOp.Operands;

        return Array.Empty<CriteriaOperator>();
    }

    public record CustomRangeFilterItem {
        public CriteriaOperator Criteria { get; init; }
        public string DisplayText { get; init; }

        public static IReadOnlyList<CustomRangeFilterItem> CreateIntervals(string fieldName, int step, int stepsCount, bool isMult, string numberDisplayFormat) {
            var prop = new OperandProperty(fieldName);
            var result = new List<CustomRangeFilterItem>();
            var start = 0;
            var end = 0;
            var firstStepIndex = isMult ? 0 : -1;

            for(var i = firstStepIndex; i < stepsCount; ++i) {
                start = isMult ? step * i : (int)Math.Pow(step, i);
                end = isMult ? start + step : (int)Math.Pow(step, i + 1);

                result.Add(new CustomRangeFilterItem() {
                    Criteria = prop >= start & prop < end,
                    DisplayText = $"from {string.Format(numberDisplayFormat, start)} to {string.Format(numberDisplayFormat, end)}"
                });
            }
            result.Add(new CustomRangeFilterItem() {
                Criteria = prop >= end,
                DisplayText = $"from {string.Format(numberDisplayFormat, end)}"
            });

            return result;
        }
    }
}
